c++primer lambda表达式¶
学习多线程的时候遇到了,特地再复习记录一下。
一,为什么使用lamda表达式 为了讲清楚这个概念,也为了方便自己以后的复习,还是要讲清楚为什么使用lamda表达式。 在c++primer中,为了引出lambda表达式这一概念,使用一段复杂的叙述,在此精简如下。 “谓词是一个可调用的表达式,其返回结果是一个能用作条件的值,一般作为算法重载的参数使用。STL中所使用的谓词分为两类:一元谓词(只接受一个函数),二元谓词(可以接受两个参数) 根据算法接受一元谓词还是二元谓词,我们传递给算法的谓词必须严格按照接受一个或两个参数。但是,如果在一个算法使用中,需要更多的参数,超出了对谓词的限制。则可以考虑lambda表达式。”
二,介绍lambda 我们可以向一个算法传递任何类别的可调用对象—此处的可调用对象有函数,函数指针,重载了函数调用运算符的类,和lambda表达式。 我们可以把lambda表达式理解为多了一个捕获列表的无名内联函数,捕获列表就是lambda接受更多参数的关键。 形式为: [捕获列表] (参数列表) -> 返回类型 { 函数体 }
值得注意的是,lambda使用尾置返回 即(-> 返回类型)。 尾置返回用于函数时通常用来表达复杂的返回值类型,但是通常可被decltype上位取代,用于lambda中可能是它的最高光时刻了,但是参数列表和返回类型可以省略掉,所以哈哈哈哈哈哈哈。
三,传参与捕获列表 传参唯一值得注意的地方是由于lambda不能有默认参数,所以其调用的实参数目和形参数目永远相等。 捕获: 一个lambda通过将局部变量包含在其捕获列表中来指出将会使用这些变量。 此部分内容不多,举例如下: [sz] (const string &a) { return a.size()>=sz }
四,捕获与返回 当定义一个lambda时,编译器生成一个相对应的类类型。(此处应有后续补充说明这种类是如何生成的,标记一下,以后补上) 当向一个函数传递一个lambda时,同时定义了一个新类型和该类型的一个对象:传递的参数即该对象。 类似的,使用auto定义一个用lambda初始化的变量时,也定义了一个从lambda生成的类型的对象。
1 值捕获与引用捕获 变量的捕获方式可以使是值或者引用。 值捕获的前提与函数值传参相同,要求是变量可以copy。 值捕获与函数值传参的区别是前者在lambda创建时copy后者在调用时copy。
引用捕获示例 [&sz] (const string &a) { return a.size()>=sz } 引用捕获和返回引用有相同的问题和限制。 如果我们采用引用方式捕获一个变量,必须保证被引用的对象在lambda执行时是存在的。 由于lambda捕获的都是局部变量,切忌出现函数结束后lambda还在执行的情况。 常用于当我们想让lambda使用ostream引用输出时。
2 隐式捕获 隐式捕获是让编译器根据lambda体中的代码推断我们使用哪些变量。 此时应在捕获列表中写一个&或=。其中&是引用捕获,=是值捕获。 示例: [=] (const string &a) { return a.size()>=sz }
混合使用示例: [=,&a] (const string &a) { return a.size()>=sz }
捕获列表中的第一个元素必须是&或=,此符号指定了默认捕获方式为引用或值。
3 可变lambda 在参数列表首加上关键字mutable,可以在lambda体中改变被捕获的变量的值。 示例 [sz] (const string &a) mutable { return a.size()>=sz }
4 指定lambda返回类型 上述lambda都只包含了一句return语句,默认情况下,如果一个lambda体包含return语句之外的任何语句则编译器假定此lambda返回void,而被推断返回void的lambda不能返回值。 当我们需要为一个lambda定义返回类型时必须使用尾置返回类型。
标记: 四 补充说明这种类是如何生成的